#include "Geometry.h"
#include <Vector3.h>
#include <cmath>

namespace soft_renderer
{
	Geometry::Geometry()
	{
	}

	Geometry::~Geometry()
	{
		//_vertexArray.clear();
		//_faceArray.clear();
		//_normalArray.clear();
	}

	std::vector<float>& Geometry::vertexArray()
	{
		return _vertexArray;
	}

	std::vector<float>& Geometry::normalArray()
	{
		return _normalArray;
	}

	std::vector<uint32_t>& Geometry::faceArray()
	{
		return _faceArray;
	}

	void Geometry::computeVertexNormals()
	{
		// 令normalArray的长度等于vertexArray
		if (_normalArray.size() != _vertexArray.size())
		{
			_normalArray.resize(_vertexArray.size());
		}

		// 清空
		std::fill(_normalArray.begin(), _normalArray.end(), 0);

		Vector3 a, b, c;
		Vector3 bc, ba;
		Vector3 n;
		for (int i = 0; i < _faceArray.size(); i += 3)
		{
			int ai = _faceArray[i];
			int bi = _faceArray[i + 1];
			int ci = _faceArray[i + 2];
			a.set(_vertexArray[ai * 3], _vertexArray[ai * 3 + 1], _vertexArray[ai * 3 + 2]);
			b.set(_vertexArray[bi * 3], _vertexArray[bi * 3 + 1], _vertexArray[bi * 3 + 2]);
			c.set(_vertexArray[ci * 3], _vertexArray[ci * 3 + 1], _vertexArray[ci * 3 + 2]);
			bc.subVectors(c, b);
			ba.subVectors(a, b);
			n.crossVectors(bc, ba);
			_normalArray[ai * 3] += n.x(); _normalArray[ai * 3 + 1] += n.y(); _normalArray[ai * 3 + 2] += n.z();
			_normalArray[bi * 3] += n.x(); _normalArray[bi * 3 + 1] += n.y(); _normalArray[bi * 3 + 2] += n.z();
			_normalArray[ci * 3] += n.x(); _normalArray[ci * 3 + 1] += n.y(); _normalArray[ci * 3 + 2] += n.z();
		}

		for (int i = 0; i < _normalArray.size(); i += 3)
		{
			n.set(_normalArray[i], _normalArray[i + 1], _normalArray[i + 2]);
			n.normalize();
			if (std::isnan(n.x()))
			{
				_normalArray[i] = 0;
				_normalArray[i + 1] = 0;
				_normalArray[i + 2] = 0;
			}
			else
			{
				_normalArray[i] = n.x();
				_normalArray[i + 1] = n.y();
				_normalArray[i + 2] = n.z();
			}
		}
	}

	void Geometry::computeBoundingBox()
	{
		boundingBox.setEmpty();
		Vector3 p;
		for (int i = 0, n = _vertexArray.size(); i < n; i += 3)
		{
			p.set(_vertexArray[i], _vertexArray[i + 1], _vertexArray[i + 2]);
			boundingBox.expandByPoint(p);
		}
	}

	
	void Geometry::appendGeometry(Geometry& geom)
	{
		uint32_t offset = _vertexArray.size() / 3;
		_vertexArray.insert(_vertexArray.end(), geom._vertexArray.begin(), geom._vertexArray.end());
		_normalArray.insert(_normalArray.end(), geom._normalArray.begin(), geom._normalArray.end());
		for (uint32_t index : geom._faceArray)
		{
			_faceArray.push_back(index + offset);
		}
	}
	
	void Geometry::appendGeometryRigid(Geometry& geom, Matrix4 m)
	{
		uint32_t offset = _vertexArray.size() / 3;

		Vector3 v;
		for (int i = 0; i < geom._vertexArray.size(); i += 3)
		{
			v.set(geom._vertexArray[i], geom._vertexArray[i + 1], geom._vertexArray[i + 2]);
			v.applyMatrix4(m);
			_vertexArray.push_back(v.x());
			_vertexArray.push_back(v.y());
			_vertexArray.push_back(v.z());
		}
		Matrix4 _normalMatrix(m);
		_normalMatrix.setTranslation({ 0, 0, 0 });
		_normalMatrix.invert();
		_normalMatrix.transpose();
		for (int i = 0; i < geom._normalArray.size(); i += 3)
		{
			v.set(geom._normalArray[i], geom._normalArray[i + 1], geom._normalArray[i + 2]);
			v.applyMatrix4(_normalMatrix);
			v.normalize();
			_normalArray.push_back(v.x());
			_normalArray.push_back(v.y());
			_normalArray.push_back(v.z());
		}
		for (uint32_t index : geom._faceArray)
		{
			_faceArray.push_back(index + offset);
		}
	}
}


